import javax.swing.JFrame;
import java.awt.event.*;
import javax.swing.*;
import clientAPI.*;


/**
 * Client GUIMain class
 * @author Torbjorn Elebjork							
 */
public class GUIMain extends JFrame implements ActionListener, MouseListener {		
	Map map;
	ServerListener reqServer;
	VideoStreamListener videoStream;
	ClientMessage cMessage;
	MapGraphics mapGraphics;
	private static final long serialVersionUID = 1L;
	private JButton changeServerButton;
	private JButton sendDriveInstructionsButton;
	private JButton scanButton;
	private JButton automaticScanButton;
	private JButton manualFocusButton;
	private JLabel serverIPLabel;
	private JLabel serverPortLabel;
	private JLabel videoServerPortLabel;
	private JLabel driveLabel;
	private JLabel turnLabel;
	private JLabel numberOfScansLabel;
	private JLabel cameraImage;
	private JTextField currentServerIPTextbox;
	private JTextField chooseServerIPTextbox;
	private JTextField chooseServerPortTextbox;
	private JTextField chooseVideoServerPortTextbox;
	private JTextField manualFocusTextbox;
	private JTextField driveTextbox;
	private JTextField turnTextbox;
	private JTextField numberOfScansTextbox;
	private static Action ArrowKeyUpAction;				//Used for key binding
	private static Action ArrowKeyDownAction;
	private static Action ArrowKeyLeftAction;
	private static Action ArrowKeyRightAction;
	private static Action ArrowKeyUpActionReleased;
	private static Action ArrowKeyDownActionReleased;
	private static Action ArrowKeyLeftActionReleased;
	private static Action ArrowKeyRightActionReleased;
	
	/**
	 * The constructor sets the horizontal and vertical sizes of the mapArray. 
	 * Adds buttons and textboxes to the panels
	 * @param xSize Horizontal size of the mapArray
	 * @param ySize Vertical size of the mapArray
	 */
	public GUIMain(int xSize,int ySize){
		super("Client");							//Name in the corner
		map = new Map(xSize,ySize);
		mapGraphics = new MapGraphics(xSize,ySize,map);
		JPanel menuPanel = new JPanel();
		JPanel menuPanel2 = new JPanel();
		JPanel videoPanel = new JPanel();
		getContentPane().add("East",videoPanel);	//Adds the video panel
		getContentPane().add("West",mapGraphics);	//Adds the map to the window
		getContentPane().add("South",menuPanel);	//Adds the menu panel
		getContentPane().add("North",menuPanel2);	//Adds the menu panel
		
		changeServerButton = new JButton("Change to Server with ip:");
		sendDriveInstructionsButton = new JButton("Send driving instructions");
		scanButton = new JButton("Scan");
		automaticScanButton = new JButton("Automatic Scan");
		manualFocusButton = new JButton("Manual control (W A S D keys)");
		currentServerIPTextbox = new  JTextField(10);
		currentServerIPTextbox.setEditable(false);
		chooseServerIPTextbox = new JTextField(10);
		chooseServerPortTextbox = new JTextField(5);
		chooseVideoServerPortTextbox = new JTextField(5);
		driveTextbox = new JTextField(3);
		turnTextbox = new JTextField(3);
		manualFocusTextbox = new JTextField(0);
		manualFocusTextbox.setVisible(true);
		numberOfScansTextbox = new JTextField(3);
		numberOfScansTextbox.setText("4");
		serverIPLabel = new JLabel("Connected to server with IP-adress:");
		serverPortLabel = new JLabel("Port:");
		videoServerPortLabel = new JLabel("Video stream port:");
		driveLabel = new JLabel("Drive (cm):");
		turnLabel = new JLabel("Turn (degrees):");
		numberOfScansLabel = new JLabel("Number of scans:");
		cameraImage = new JLabel("");
		
		menuPanel.add(manualFocusButton);
		menuPanel.add(scanButton);
		menuPanel.add(automaticScanButton);
		videoPanel.add(cameraImage);	
		menuPanel2.add(changeServerButton);
		menuPanel2.add(chooseServerIPTextbox);
		menuPanel2.add(serverPortLabel);
		menuPanel2.add(chooseServerPortTextbox);
		menuPanel2.add(videoServerPortLabel);
		menuPanel2.add(chooseVideoServerPortTextbox);
		menuPanel.add(sendDriveInstructionsButton);	
		menuPanel.add(numberOfScansLabel);
		menuPanel.add(numberOfScansTextbox);
		menuPanel.add(driveLabel);
		menuPanel.add(driveTextbox);	
		menuPanel.add(turnLabel);
		menuPanel.add(turnTextbox);
		menuPanel2.add(serverIPLabel);
		menuPanel2.add(currentServerIPTextbox);
		menuPanel.add(manualFocusTextbox);
		
		chooseServerIPTextbox.setText("130.243.199.163"); 			//Temporary 192.168.0.10   212.25.149.232  aland: 212.25.153.76
		chooseServerPortTextbox.setText("46369");				//130.238.246.120 port 46369
		chooseVideoServerPortTextbox.setText("46370");
		driveTextbox.setText("0");
		turnTextbox.setText("0");
		changeServerButton.addActionListener(this);
		automaticScanButton.addActionListener(this);
		scanButton.addActionListener(this);
		sendDriveInstructionsButton.addActionListener(this);
		manualFocusButton.addActionListener(this);
		mapGraphics.addMouseListener(this);
	    addMouseListener(this);
	   
	    ArrowKeyUpAction = new ArrowKeyUpAction();
	    ArrowKeyDownAction = new ArrowKeyDownAction();
	    ArrowKeyLeftAction = new ArrowKeyLeftAction();
	    ArrowKeyRightAction = new ArrowKeyRightAction();
	    ArrowKeyUpActionReleased = new ArrowKeyUpActionReleased();
	    ArrowKeyDownActionReleased = new ArrowKeyDownActionReleased();
	    ArrowKeyLeftActionReleased = new ArrowKeyLeftActionReleased();
	    ArrowKeyRightActionReleased = new ArrowKeyRightActionReleased(); 
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"),"VK_UP_Action");
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"),"VK_DOWN_Action");			//KeyEvent.VK_DOWN, 0
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"),"VK_LEFT_Action");
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"),"VK_RIGHT_Action");
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"),"VK_UP_Action_Rel");
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"),"VK_DOWN_Action_Rel");
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"),"VK_LEFT_Action_Rel");
	    mapGraphics.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"),"VK_RIGHT_Action_Rel");
	    mapGraphics.getActionMap().put("VK_UP_Action",ArrowKeyUpAction);   
	    mapGraphics.getActionMap().put("VK_DOWN_Action",ArrowKeyDownAction );
	    mapGraphics.getActionMap().put("VK_LEFT_Action",ArrowKeyLeftAction );
	    mapGraphics.getActionMap().put("VK_RIGHT_Action",ArrowKeyRightAction );
	    mapGraphics.getActionMap().put("VK_UP_Action_Rel",ArrowKeyUpActionReleased);
	    mapGraphics.getActionMap().put("VK_DOWN_Action_Rel",ArrowKeyDownActionReleased);
	    mapGraphics.getActionMap().put("VK_LEFT_Action_Rel",ArrowKeyLeftActionReleased );
	    mapGraphics.getActionMap().put("VK_RIGHT_Action_Rel",ArrowKeyRightActionReleased );
	    
	    cMessage = new ClientMessage(Turn.STOP,Drive.STOP);
		pack();										
		setDefaultCloseOperation(EXIT_ON_CLOSE);					//Terminate the program when windows closed
	}
	
	/**
	 * Starts the GUI
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String [] args) throws InterruptedException {
		GUIMain guiMain = new GUIMain(400,280); 			
		guiMain.setVisible(true);
	}
	
	/**
	 * Sets the ip adress / connection status in the textbox currentServerIPTextbox
	 * @param ipInfo
	 */
	void setCurrentServerIPTextbox(String ipInfo){
		currentServerIPTextbox.setText(ipInfo);
	}
	
	/**
	 * Updates the image on the video
	 * @param imageIcon
	 */
	void setCameraImage(ImageIcon imageIcon){
		cameraImage.setIcon(imageIcon);
	}
	
	/**
	 * Triggered by buttons
	 * @param ae
	 */
	public void actionPerformed(ActionEvent ae){
		if(ae.getSource()==changeServerButton){	
			cMessage = new ClientMessage(0,0,0); 		//test
			if(reqServer!=null){
				reqServer.setRun(false);
				cMessage.setTerminate(true);
				reqServer.sendMessage(cMessage);				
			}
			reqServer = new ServerListener(chooseServerIPTextbox.getText(), Integer.parseInt(chooseServerPortTextbox.getText()),this,mapGraphics, map);
			reqServer.start();							// Start new thread
			currentServerIPTextbox.setText(chooseServerIPTextbox.getText());
			videoStream = new VideoStreamListener(chooseServerIPTextbox.getText(),Integer.parseInt(chooseVideoServerPortTextbox.getText()),this);
			videoStream.start();
		}
		else if(ae.getSource()==sendDriveInstructionsButton){
			try{
				cMessage = new ClientMessage(Integer.parseInt(turnTextbox.getText()),Integer.parseInt(driveTextbox.getText()),Integer.parseInt(numberOfScansTextbox.getText()));
				reqServer.sendMessage(cMessage);
			}
			catch(Exception e){
				turnTextbox.setText("0");
				driveTextbox.setText("0");
				numberOfScansTextbox.setText("4");
			}
		}
		else if(ae.getSource()==automaticScanButton){
			cMessage = new ClientMessage(true);
			reqServer.sendMessage(cMessage);
		}
		else if(ae.getSource()==scanButton){
			try{
				cMessage = new ClientMessage(0,0,Integer.parseInt(numberOfScansTextbox.getText()));
				reqServer.sendMessage(cMessage);
			}
			catch(Exception e){
				turnTextbox.setText("0");
				driveTextbox.setText("0");
				numberOfScansTextbox.setText("4");
			}
		}
		else if(ae.getSource()==manualFocusButton){
			manualFocusTextbox.requestFocus();
		}
		else{	
		}
	}
	
	/**
	 * Triggered when the mouse is pressed on the map
	 * @param mouse
	 */
	@Override
	public void mousePressed(MouseEvent mouse) {
		int x = mouse.getX();
		int y = mouse.getY();
		if(x>=0 && x<=mapGraphics.getGraphicalXSize() && y>=0 && y<=mapGraphics.getGraphicalYSize()){
			if(map.getStateAt(x/mapGraphics.getPixelSize(), y/mapGraphics.getPixelSize())==0){
				map.setStateAt(x/mapGraphics.getPixelSize(), y/mapGraphics.getPixelSize(), 4);
			}
		}
		repaint();
	}
	
	
	/**
	 * @deprecated MouseListener interface
	 */
	@Override
	public void mouseClicked(MouseEvent arg0){
	}
	/**
	 * @deprecated MouseListener interface
	 */
	@Override
	public void mouseEntered(MouseEvent arg0) {
	}
	/**
	 * @deprecated MouseListener interface
	 */
	@Override
	public void mouseExited(MouseEvent arg0) {	
	}
	/**
	 * @deprecated MouseListener interface
	 */
	@Override
	public void mouseReleased(MouseEvent arg0) {
	}
	
	
	class ArrowKeyUpAction extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			if(cMessage.getD()!=Drive.FORWARD){							// To stop multiple fire of press event, better soultion? keylistener works different?
				cMessage = new ClientMessage(Turn.UNCHANGED,Drive.FORWARD);
				reqServer.sendMessage(cMessage);
				System.out.println("FORWARD");
			}		
	    } 
	} 	
	class ArrowKeyUpActionReleased extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			cMessage = new ClientMessage(Turn.UNCHANGED,Drive.STOP);
			reqServer.sendMessage(cMessage);
			System.out.println("STOP (up)");	
		} 
	} 	
	
	
	class ArrowKeyDownAction extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			//Change focus away from textboxes here!
			if(cMessage.getD()!=Drive.BACKWARD){	
				cMessage = new ClientMessage(Turn.UNCHANGED,Drive.BACKWARD);
				reqServer.sendMessage(cMessage);
				System.out.println("BACKWARD");
			}
	    } 
	} 
	
	class ArrowKeyDownActionReleased extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			cMessage = new ClientMessage(Turn.UNCHANGED,Drive.STOP);
			reqServer.sendMessage(cMessage);
			System.out.println("STOP (down)");
	    } 
	} 
	
	class ArrowKeyLeftAction extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			//Change focus away from textboxes here!
			if(cMessage.getT()!=Turn.LEFT){
				cMessage = new ClientMessage(Turn.LEFT,Drive.UNCHANGED);
				reqServer.sendMessage(cMessage);
				System.out.println("LEFT");
			}
	    } 
	} 
	
	class ArrowKeyLeftActionReleased extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			cMessage = new ClientMessage(Turn.STOP,Drive.UNCHANGED);
			reqServer.sendMessage(cMessage);
			System.out.println("STOP (left)");
	    } 
	} 
	
	class ArrowKeyRightAction extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			if(cMessage.getT()!=Turn.RIGHT){
				cMessage = new ClientMessage(Turn.RIGHT,Drive.UNCHANGED);
				reqServer.sendMessage(cMessage);
				System.out.println("RIGHT");
			}
	    } 
	} 
	
	class ArrowKeyRightActionReleased extends AbstractAction {
		private static final long serialVersionUID = 1L;
		public void actionPerformed(ActionEvent ae) {
			manualFocusTextbox.requestFocus();
			cMessage = new ClientMessage(Turn.STOP,Drive.UNCHANGED);
			reqServer.sendMessage(cMessage);
			System.out.println("STOP (right)");
	    } 
	} 
}




